/**
 * 
 */
package cen5501c.common;

import java.util.ArrayList;
import java.util.List;

/**
 * This class consists of static methods that handle the encoding and decoding 
 * work on the commands. 
 * @author Jiangyan Xu
 */
public class CmdParser {

	public static String cmdToString(CmdBase command) {
		StringBuilder sb = new StringBuilder();
		sb.append('<');
		sb.append(command.getOperation());
		List<String> arg_list = command.getArgList(); //possibly empty
		boolean has_multiple_lines = (command instanceof FileListCmd || command instanceof FileContentCmd);
		int end_index;
		if (has_multiple_lines) {
			end_index = arg_list.size() - 2;
		} else {
			end_index = arg_list.size() - 1;
		}
		for (int i = 0; i <= end_index; i++) {
			String arg = arg_list.get(i);
			sb.append(',');
			sb.append(arg);
		}
		sb.append(">\n");
		if (has_multiple_lines) {
			sb.append(arg_list.get(arg_list.size() - 1));
		}
		return sb.toString();
	}

	public static CmdBase cmdFromString(String command) throws Exception {
		CmdBase cmd = CommandFactory.createCmd(extractOperation(command),
				extractArgList(command));
		return cmd;
	}

	protected static String extractOperation(String command) {
		String ret = null;
		int pos_comma = command.indexOf(",");
		if (pos_comma == -1) {
			//no argument, just exclude '<' and '>\n'
			ret = command.substring(1, command.indexOf(">"));
		} else {
			ret = command.substring(1, pos_comma);
		}
		return ret;
	}

	/**
	 * This doesn't work with standard RFC822 time format but works
	 * with the returned value from CISE sample server.
	 * TODO improve the parsing with std. RFC822
	 */
	protected static List<String> extractArgList(String cmd) {
		List<String> ret = new ArrayList<String>();
		boolean has_multi_lines = (cmd.split("\n", 2).length > 1);
		//line 1 excluding '<' and '>\n'
		String line1 = cmd.substring(1, cmd.indexOf(">"));

		String[] elements = line1.split(",");
		if (elements.length == 1) {
			//no argument, do nothing
		} else {
			//skip the first one, which is the operation
			for (int i = 1; i < elements.length; i++) {
				ret.add(elements[i]);
			}
		}
		if (has_multi_lines) {
			//only split the command into 2 and the 2nd part, no matter how
			//many lines it has, is considered as (the last) one argument in the arg list
			ret.add(cmd.split("\n", 2)[1]);
		}
		return ret;
	}
}
